#include <unordered_map>
#include <vector>
#include <cassert>
#include <memory>
#include "symtable.hpp"

// 作用域计数器，用于为符号表生成唯一标号
static int symbol_table_cnt = 0;

// 符号表类型
using symbol_table_t = std::unordered_map<std::string, std::shared_ptr<symbol_value>>;

// 作用域栈，存储符号表标号和对应符号表的指针
using symbol_table_stack_t = std::vector<std::pair<int, std::unique_ptr<symbol_table_t>>>;
static symbol_table_stack_t symbol_table_stack;

// 进入新的作用域
void enter_code_block()
{
    symbol_table_stack.emplace_back(symbol_table_cnt++, std::make_unique<symbol_table_t>());
}

// 离开当前作用域
void exit_code_block()
{
    assert(!symbol_table_stack.empty() && "Symbol table stack underflow");
    symbol_table_stack.pop_back();
}

// 返回当前作用域的标号
std::string current_code_block()
{
    assert(!symbol_table_stack.empty() && "No active symbol table");
    return "SYM_TABLE_" + std::to_string(symbol_table_stack.back().first) + "_";
}

// 在符号表中寻找符号，返回其所在符号表的标号和其本身的迭代器
static std::pair<int, symbol_table_t::iterator> find_iter(const std::string &symbol)
{
    for (auto rit = symbol_table_stack.rbegin(); rit != symbol_table_stack.rend(); ++rit)
    {
        auto it = rit->second->find(symbol);
        if (it != rit->second->end())
        {
            return {rit->first, it};
        }
    }
    return {-1, symbol_table_t::iterator{}};
}

// 插入符号定义
void insert_symbol(const std::string &symbol, symbol_type type, int value)
{
    assert(!symbol_table_stack.empty() && "No active symbol table to insert symbol");

    auto symval = std::make_shared<symbol_value>(symbol_value{type, value});
    (*symbol_table_stack.back().second)[symbol] = symval;
}

// 确认符号定义是否存在，若存在返回1，否则返回0
int exist_symbol(const std::string &symbol)
{
    auto [symtid, it] = find_iter(symbol);
    return symtid != -1;
}

// 查询符号定义，返回该符号所在符号表标号和指向这个符号值的共享指针。
// 若符号不存在，返回的表号为-1，符号类型为UND。
std::pair<std::string, std::shared_ptr<const symbol_value>> query_symbol(const std::string &symbol)
{
    auto [symtid, it] = find_iter(symbol);
    std::string table_name = "SYM_TABLE_" + std::to_string(symtid) + "_";

    if (symtid == -1) // 符号不存在
    {
        auto symval = std::make_shared<symbol_value>(symbol_value{SYM_TYPE_UND, -1});
        return {table_name, symval};
    }

    return {table_name, it->second};
}
